/*
 * fileup.c - file upload
 * Clunix, cezanne@clunix.com, 2007.7
 *
 * Copyright (c) 2001-2007 by Clunix Inc. All Rights Reserved.
 */

#include "config.h"

#include "dua.h"
#include "dush_common.h"

#define	UPDN_CHUNKSIZE	8192

static dush_err_t
req_file_create(ebc_t *ec, ebc_addr_t *paddr, const char *src_fname, const char *dst_path, dush_fid_t *pfid, dush_fileopt_t opt)
{
	sr_t	*sr_file_info;
	dush_err_t	err;
	sr_t	*sr_res;

	sr_file_info = sr_create_dir();
	sr_append(sr_file_info, sr_create_int(ST_INT, DUSH_FILEOP_CREATE));
	sr_append(sr_file_info, sr_create_str(ST_STR, src_fname));
	sr_append(sr_file_info, sr_create_str(ST_STR, dst_path));
	sr_append(sr_file_info, sr_create_int(ST_INT, opt));

	if (ebc_dcall_nofree(ec, paddr, sr_file_info, &sr_res) != EBC_OK)
		return -ERR_DUSH_EBC;

	err = sr_geti_int(sr_res, 0);
	if (err == DUSH_OK)
		*pfid = sr_geti_int(sr_res, 1);
	sr_free(sr_res);

	return err;
}

static dush_err_t
req_file_close(ebc_t *ec, ebc_addr_t *paddr, dush_fid_t fid, ECMBOOL done)
{
	sr_t	*sr_file_info;
	dush_err_t	err;
	sr_t	*sr_res;

	sr_file_info = sr_create_dir();
	sr_append(sr_file_info, sr_create_int(ST_INT, DUSH_FILEOP_CLOSE));
	sr_append(sr_file_info, sr_create_int(ST_INT, fid));
	sr_append(sr_file_info, sr_create_bool(ST_BOOL, done));

	if (ebc_dcall_nofree(ec, paddr, sr_file_info, &sr_res) != EBC_OK)
		return -ERR_DUSH_EBC;

	err = sr_get_int(sr_res);
	sr_free(sr_res);

	return err;
}

static dush_err_t
req_file_write(ebc_t *ec, ebc_addr_t *paddr, dush_fid_t fid, ecm_uint64 off, ecm_uint8 *buf, ecm_size_t size)
{
	sr_t	*sr_file_info;
	dush_err_t	err;
	sr_t	*sr_res;

	sr_file_info = sr_create_dir();
	sr_append(sr_file_info, sr_create_int(ST_INT, DUSH_FILEOP_WRITE));
	sr_append(sr_file_info, sr_create_int(ST_INT, fid));
	sr_append(sr_file_info, sr_create_ll(ST_LL, off));
	sr_append(sr_file_info, sr_create_oct(ST_OCT, size, buf));

	if (ebc_dcall_nofree(ec, paddr, sr_file_info, &sr_res) != EBC_OK)
		return -ERR_DUSH_EBC;

	err = sr_get_int(sr_res);
	sr_free(sr_res);

	return err;
}

static dush_err_t
req_file_remove(ebc_t *ec, ebc_addr_t *paddr, const char *path, dush_fileopt_t opt)
{
	sr_t	*sr_file_info;
	dush_err_t	err;
	sr_t	*sr_res;

	sr_file_info = sr_create_dir();
	sr_append(sr_file_info, sr_create_int(ST_INT, DUSH_FILEOP_REMOVE));
	sr_append(sr_file_info, sr_create_str(ST_STR, path));
	sr_append(sr_file_info, sr_create_int(ST_INT, opt));

	if (ebc_dcall_nofree(ec, paddr, sr_file_info, &sr_res) != EBC_OK)
		return -ERR_DUSH_EBC;

	err = sr_get_int(sr_res);
	sr_free(sr_res);

	return err;
}

dush_err_t
dua_file_upload(const char *modname, const char *src_path, const char *dst_path, dush_fileopt_t opt)
{
	int	fd;
	ebc_addr_t	addr;
	ecm_uint8	buf[UPDN_CHUNKSIZE];
	ecm_size_t	size;
	dush_fid_t	fid;
	ecm_uint64	off;
	dush_err_t	err;

	ebc_build_addr(&addr, ".", modname, "file");

	if ((fd = ecm_open(src_path, ECM_O_RDONLY)) < 0)
		return -ERR_DUSH_INVALIDARG;

	err = req_file_create(ec, &addr, ecm_basename(src_path), dst_path, &fid, opt);
	if (err != DUSH_OK) {
		ecm_close(fd);
		return err;
	}

	off = 0;
	while (ECM_TRUE) {
		size = UPDN_CHUNKSIZE;
		if (!ecm_read(fd, (char *)buf, &size)) {
			req_file_close(ec, &addr, fid, ECM_FALSE);
			ecm_close(fd);
			return -ERR_DUSH_GENERAL;
		}
		if (size == 0)
			break;
		err = req_file_write(ec, &addr, fid, off, buf, size);
		if (err != DUSH_OK) {
			req_file_close(ec, &addr, fid, ECM_FALSE);
			ecm_close(fd);
			return err;
		}
		off += size;
	}
	req_file_close(ec, &addr, fid, ECM_TRUE);
	ecm_close(fd);
	return DUSH_OK;
}

dush_err_t
dua_file_delete(const char *modname, const char *dst_path, dush_fileopt_t opt)
{
	ebc_addr_t	addr;

	ebc_build_addr(&addr, ".", modname, "file");

	return req_file_remove(ec, &addr, dst_path, opt);
}
